using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.Globalization;
using System.Threading;
using System.Windows.Forms;
using System.Drawing;
using System.Text;

using Routine.Utilities;

using Styx;
using Styx.CommonBot;
using Styx.CommonBot.Routines;
using Styx.Helpers;
using Styx.TreeSharp;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using Styx.Common.Helpers;
using Styx.Pathing;

using CommonBehaviors.Actions;

using Singular.Dynamics;
using Singular.Helpers;
using Singular.Managers;
using Singular.Settings;

using Action = Styx.TreeSharp.Action;
//
using Rest = Singular.Helpers.Rest;
//
using FarmerJoe.Helpers;



namespace destro
{
    public class Routine : CombatRoutine
    {
        /// <summary>
        /// The name of this CombatRoutine
        /// </summary>
        /// <value>
        /// The name.
        /// </value>
        public override string Name { get { return "Destro"; } }


        /// <summary>
        /// The <see cref="T:Styx.WoWClass"/> to be used with this routine
        /// </summary>
        /// <value>
        /// The class.
        /// </value>
        public override WoWClass Class { get { return WoWClass.Warlock; } }


        private Composite _combat, _buffs;


        public override Composite CombatBehavior { get { return _combat; } }
        public override Composite PreCombatBuffBehavior { get { return _buffs; } }
        public override Composite CombatBuffBehavior { get { return _buffs; } }

        public DateTime LastCastTime = DateTime.Now;

        public override void Initialize()
        {
            _combat = CreateCombat();
            _buffs = CreateBuffs();
        }

		private int addCount()
        {
            int count = 0;
            foreach (WoWUnit u in ObjectManager.GetObjectsOfType<WoWUnit>(true, true))
            {
                if (u.IsAlive
                    && StyxWoW.Me.CurrentTarget != null
                    && u.Guid != StyxWoW.Me.Guid
                    && !u.IsFriendly
                    && (u.IsHostile || u.IsNeutral)
                    && !u.IsCritter
                    && u.Location.Distance(StyxWoW.Me.Location) <= 30
                    && (u.IsTargetingMyPartyMember || u.IsTargetingMyRaidMember || u.IsTargetingMeOrPet || u.IsTargetingAnyMinion))
                {
                    count++;
                }
            }
            return count;
        }

		private bool IsTargetBoss()
        {
            if (StyxWoW.Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.WorldBoss ||
               (StyxWoW.Me.CurrentTarget.Level >= 90 && StyxWoW.Me.CurrentTarget.Elite && StyxWoW.Me.CurrentTarget.MaxHealth > 6000000))
                return true;

            else return false;
        }

		private bool hasAggro()
        {
            foreach (WoWUnit u in ObjectManager.GetObjectsOfType<WoWUnit>(true, true))
            {
                if ((StyxWoW.Me.GroupInfo.IsInParty || StyxWoW.Me.GroupInfo.IsInRaid) && u.Guid != StyxWoW.Me.Guid && !u.IsFriendly && (u.IsHostile || u.IsNeutral) && !u.IsCritter && u.CurrentTarget.Guid == StyxWoW.Me.Guid) return true;
                //if (u.Guid != StyxWoW.Me.Guid && !u.IsFriendly && (u.IsHostile || u.IsNeutral) && !u.IsCritter && u.CurrentTarget.Guid == StyxWoW.Me.Guid) return true;
            }
            return false;
        }

        private int RAOEaddCount()
        {
            int count = 0;
            foreach (WoWUnit u in ObjectManager.GetObjectsOfType<WoWUnit>(true, true))
            {
                if (u.IsAlive
                    && StyxWoW.Me.CurrentTarget != null
                    && u.Guid != StyxWoW.Me.Guid
                    && !u.IsFriendly
                    && (u.IsHostile || u.IsNeutral)
                    && !u.IsCritter
                    && u.Location.Distance(StyxWoW.Me.CurrentTarget.Location) <= 10//&& u.IsWithinMeleeRange
                    && (u.IsTargetingMyPartyMember || u.IsTargetingMyRaidMember || u.IsTargetingMeOrPet || u.IsTargetingAnyMinion))
                {
                    count++;
                }
            }
            return count;
        }

        Composite CreateBuffs()
        {
            return new PrioritySelector(
				Cast("Dark Intent", ret => !StyxWoW.Me.HasAura("Dark Intent") && !StyxWoW.Me.Mounted),
				new Decorator( ret => !StyxWoW.Me.HasAura("Grimoire of Sacrifice") && !StyxWoW.Me.Mounted,
					new PrioritySelector(
                        //new WaitContinue(2, ret=> !SpellManager.GlobalCooldown && !StyxWoW.Me.IsCasting, new ActionAlwaysSucceed()),
						Cast("Soulburn", ret => !StyxWoW.Me.HasAura("Soulburn") && !StyxWoW.Me.GotAlivePet && !StyxWoW.Me.HasAura("Grimoire of Sacrifice")),
						new Decorator(ret => StyxWoW.Me.GotAlivePet && StyxWoW.Me.CastingSpell != null && StyxWoW.Me.CastingSpell.Name == "Summon Imp",
							new Styx.TreeSharp.Action(r => SpellManager.StopCasting())),
						Cast("Summon Imp", ret => StyxWoW.Me.HasAura("Soulburn") && !StyxWoW.Me.GotAlivePet && !StyxWoW.Me.HasAura("Grimoire of Sacrifice")),
						Cast("Summon Imp", ret => !StyxWoW.Me.GotAlivePet && !StyxWoW.Me.HasAura("Grimoire of Sacrifice")),
						Cast("Grimoire of Sacrifice", ret => StyxWoW.Me.GotAlivePet && !StyxWoW.Me.HasAura("Grimoire of Sacrifice"))
					)
				),
				new Decorator(ret =>
					!StyxWoW.Me.HasAura("Visions of Insanity"),
					new Action(abc =>
					{
						WoWItem item = StyxWoW.Me.BagItems.Find(ret => ret.Entry == 86569);
                            if (item != null) item.Use(); 
					}))
				
			);
			
        }

		
		
        Composite CreateCombat()
        {
			return new Decorator ( ctz => !StyxWoW.Me.Mounted && !StyxWoW.Me.HasAura("Drink") && !StyxWoW.Me.HasAura("Food") && !StyxWoW.Me.HasAura("First Aid"),
            new PrioritySelector(


                // Interrupt please.
                Spell.CastOnGround("Shadowfury", ret => StyxWoW.Me.CurrentTarget.Location, 
					ret => StyxWoW.Me.CurrentTarget.IsCasting && StyxWoW.Me.CurrentTarget.CanInterruptCurrentSpellCast && !SpellManager.Spells["Shadowfury"].Cooldown),
                Cast("Arcane Torrent", ret => StyxWoW.Me.CurrentTarget.IsCasting && StyxWoW.Me.CurrentTarget.CanInterruptCurrentSpellCast && !SpellManager.Spells["Shadowfury"].Cooldown && StyxWoW.Me.CurrentTarget.Distance <= 8),
                
				// Defensive CD
                //Cast("Soul Shatter", ret => hasAggro()),
				Cast("Unending Resolve", ret => StyxWoW.Me.HealthPercent < 70),
				Cast("Dark Regeneration", ret => StyxWoW.Me.HealthPercent < 75),
				Cast("Dark Bargain", ret => StyxWoW.Me.HealthPercent < 70 && !StyxWoW.Me.HasAura("Unending Resolve")),

				new Decorator( ret => StyxWoW.Me.HealthPercent < 50,
					new PrioritySelector(
						Cast("Soulburn", ret => !StyxWoW.Me.HasAura("Soulburn")),
						Cast("Harvest Life"),
						Cast("Drain Life")
					)
				),
				//Cast("Harvest Life", ret => StyxWoW.Me.HealthPercent < 50),
				//Cast("Drain Life", ret => StyxWoW.Me.HealthPercent < 50),
				Cast("Life Tap", ret => StyxWoW.Me.ManaPercent < 15),
				Cast("Unending Breath", ret => StyxWoW.Me.IsSwimming),
				// Heal yourself
				Cast("Healthstone", ret => StyxWoW.Me.HealthPercent < 60),
				new Decorator( ret => StyxWoW.Me.HealthPercent < 45,
					new PrioritySelector(
						Cast("Soulburn", ret => !StyxWoW.Me.HasAura("Soulburn")),
						Cast("Harvest Life"),
						Cast("Drain Life")
					)
				),

				Cast("Summon Doomguard", ret => IsTargetBoss()),
				Cast("Dark Soul: Instability"),

                new Action(ret => { UseTrinkets(); return RunStatus.Failure; }),

				//AOE ================
				new Decorator( ret => addCount() > 2,
					new PrioritySelector(
						Spell.CastOnGround("Shadowfury", ret => StyxWoW.Me.CurrentTarget.Location, ret=>true),
						Spell.CastOnGround("Rain of Fire", ret => StyxWoW.Me.CurrentTarget.Location, ret => StyxWoW.Me.CurrentTarget.ActiveAuras.Any(u => u.Key == "Immolate")),
						Spell.Cast("Fire and Brimstone", ret => !StyxWoW.Me.ActiveAuras.Any(u => u.Key == "Fire and Brimstone")),
						Spell.Cast("Chaos Bolt", ret => StyxWoW.Me.ActiveAuras.Any(u => u.Key == "Fire and Brimstone")),// ret => StyxWoW.Me.ActiveAuras.Any(u => u.Key == "Havoc")),
						Spell.Cast("Immolate", ret => TargetDebuffDuration("Immolate") < 5),
						Spell.Cast("Immolate", ret => StyxWoW.Me.ActiveAuras.Any(u => u.Key == "Fire and Brimstone")),
						//Spell.Cast("Havoc", ret => !StyxWoW.Me.ActiveAuras.Any(u => u.Key == "Havoc")),
						Spell.Cast("Incinerate")//, ret => StyxWoW.Me.ActiveAuras.Any(u => u.Key == "Havoc"))
					)
				),
				
				// Normal Rotation
				new Decorator(ret =>StyxWoW.Me.CurrentTarget.HealthPercent <= 20 && StyxWoW.Me.CastingSpell != null && !SpellManager.Spells["Shadowburn"].Cooldown && SpellManager.CanCast("Shadowburn"),
					new Styx.TreeSharp.Action(r => SpellManager.StopCasting())),
				Spell.Cast("Shadowburn"), //ret=> StyxWoW.Me.CurrentTarget.HealthPercent <= 20),
				Cast("Curse of the Elements", ret => !StyxWoW.Me.CurrentTarget.ActiveAuras.Any(u => u.Key == "Curse of the Elements") && IsTargetBoss()),
				Spell.Cast("Incinerate", ret=> StyxWoW.Me.ActiveAuras.Any(u => u.Key == "Backlash")),			
				Spell.Cast("Conflagrate", ret=> !StyxWoW.Me.ActiveAuras.Any(u => u.Key == "Backdraft")),
				new Decorator(ret => StyxWoW.Me.GetCurrentPower(WoWPowerType.BurningEmbers) < 20 && StyxWoW.Me.CastingSpell != null && StyxWoW.Me.CastingSpell.Name == "Chaos Bolt",
					new Styx.TreeSharp.Action(r => SpellManager.StopCasting())),
				Spell.Cast("Chaos Bolt",ret=>StyxWoW.Me.GetCurrentPower(WoWPowerType.BurningEmbers) >= 20),
				new Decorator(ret => TargetDebuffDuration("Immolate") >= 5 && StyxWoW.Me.CastingSpell != null && StyxWoW.Me.CastingSpell.Name == "Immolate",
					new Styx.TreeSharp.Action(r => SpellManager.StopCasting())),
				Cast("Immolate", ret => TargetDebuffDuration("Immolate") < 5),
				Spell.Cast("Incinerate")			
            )
		);
        }

        void UseTrinkets()
        {
            var firstTrinket = StyxWoW.Me.Inventory.Equipped.Trinket1;
            var secondTrinket = StyxWoW.Me.Inventory.Equipped.Trinket2;


            if(firstTrinket != null && CanUseEquippedItem(firstTrinket))
                firstTrinket.Use();


            if(secondTrinket != null && CanUseEquippedItem(secondTrinket))
                secondTrinket.Use();


        }
        private static bool CanUseEquippedItem(WoWItem item)
        {
            // Check for engineering tinkers!
            string itemSpell = Lua.GetReturnVal<string>("return GetItemSpell(" + item.Entry + ")", 0);
            if (string.IsNullOrEmpty(itemSpell))
                return false;


            return item.Usable && item.Cooldown <= 0;
        }

        public static int CurseCount
        {
            get
            {
                int result = 0;

                result += StyxWoW.Me.CurrentTarget.HasMyAura("Corruption") ? 1 : 0;
                result += StyxWoW.Me.CurrentTarget.HasMyAura("Agony") ? 1 : 0;
                result += StyxWoW.Me.CurrentTarget.HasMyAura("Unstable Affliction") ? 1 : 0;
                
                return result;
            }
			//return result;
        }

        private delegate T Selection<out T>(object context);
        Composite Cast(string spell, Selection<bool> reqs = null)
        {
            return
                new Decorator(
                    ret => ((reqs != null && reqs(ret)) || (reqs == null)) && SpellManager.CanCast(spell),
                    new Action(ret => SpellManager.Cast(spell)));
        }

        public static double TargetDebuffDuration(String spellName)
        {
            return StyxWoW.Me.CurrentTarget.GetAuraTimeLeft(spellName, true).TotalSeconds;
        }

        public static TimeSpan GetSpellCooldown(string spell)
        {
            SpellFindResults results;
            if (SpellManager.FindSpell(spell, out results))
            {
                if (results.Override != null)
                    return results.Override.CooldownTimeLeft;
                return results.Original.CooldownTimeLeft;
            }


            return TimeSpan.MaxValue;
        }
    }
}